#pragma once

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstring>
#include <string>

const std::string g_pathname = ".";
const int g_proj_id = 0x66;
const int g_default_size = 4096; // 共享内存的大小必须是4kb的整数倍  4kb对齐（内核层面）

class SharedMemory
{
public:
    SharedMemory(int size = g_default_size) : _size(size), _startptr(nullptr), _windex(0), _rindex(0), _num(nullptr), _data_start(nullptr)
    {
    }
    ~SharedMemory()
    {
    }

    // key vs shmid
    // 1.key: 只有内核使用，用来标识shm的唯一性
    // 2.shmid: 给用户使用，用来进行访问shm
    bool Create()
    {
        return CreateHelper(IPC_CREAT | IPC_EXCL | 0666);
    }

    bool Get()
    {
        return CreateHelper(IPC_CREAT);
    }

    bool Attach()
    {
        _startptr = shmat(_shmid, nullptr, 0);
        if ((long long)_startptr == -1)
        {
            perror("shmat error");
            return false;
        }
        _num = (int *)_startptr;
        _data_start = _startptr + sizeof(int);
        Setzero();
        return true;
    }

    bool Detach()
    {
        int n = shmdt(_startptr);
        if (n < 0)
        {
            perror("shmdt error");
            return false;
        }
        return true;
    }

    bool RemoveShm()
    {
        int n = shmctl(_shmid, IPC_RMID, nullptr);
        if (n < 0)
        {
            perror("shmctl error");
            return false;
        }
        std::cout << "删除共享内存成功" << std::endl;
        return true;
    }

    void AddChar(char ch)
    {
        if (*_num == _size)
            return;
        ((char *)_data_start)[_windex++] = ch;
        _windex %= _size;
        (*_num)++;
    }

    void Setzero()
    {
        *_num = 0;
    }

    void PopAddr(char* ch)
    {
        if (*_num == 0)
            return;
        *ch = ((char *)_data_start)[_rindex++];
        _rindex %= _size;
        (*_num)--;
    }

    void Know()
    {
        struct shmid_ds ds;
        shmctl(_shmid, IPC_STAT, &ds);
        ds.shm_atime;
        ds.shm_nattch;
        ds.shm_perm.__key;
        ds.shm_cpid;
        
    }

    // void AddInt(){}
    // void AddString(){}

private:
    key_t _key;
    int _size;
    int _shmid;
    void *_startptr;
    int _windex;
    int _rindex;
    int *_num;
    void *_data_start;
    bool CreateHelper(int flags)
    {
        _key = ftok(g_pathname.c_str(), g_proj_id);
        if (_key < 0)
        {
            perror("ftok error");
            exit(1);
        }
        printf("创建键值成功 key = %#x\n", _key);
        _shmid = shmget(_key, _size, flags);
        if (_shmid < 0)
        {
            perror("shmget error");
            exit(2);
        }
        printf("创建共享内存成功 shmid = %d\n", _shmid);
        return true;
    }
};